<template>
  <div class="flex-col">
    <div v-if="type !== 'static'" class="groupLabel">仿真推演</div>
    <div class="flex gap-24">
      <n-form
        ref="$form"
        label-placement="left"
        label-align="right"
        require-mark-placement="left"
        :label-width="132"
        :show-label="type === 'static'"
        class="flex-1"
      >
        <n-form-item label="测试进度">
          <MyProgress
            :color="statusResult.color"
            :percentage="progress"
            :text="statusResult.text"
            :gradient="statusResult.gradient"
          />
        </n-form-item>
        <n-form-item class="output" label="执行输出">
          <MyTab v-model:value="outputState.currentTab" :options="outputState.tabs" />
          <div class="my-card mt-16">
            <n-spin :show="outputState.loading">
              <n-scrollbar ref="$output" :style="{ height: `${height}px` }" @scroll="onScroll">
                <div v-for="(item, index) in currentTabList" :key="index" class="output-text">
                  {{ item.content }}
                </div>
              </n-scrollbar>
            </n-spin>
          </div>
        </n-form-item>
      </n-form>
      <div v-if="type !== 'static'" class="flex-col flex-1 pb-24">
        <div v-if="appStore.isDeep" class="deep-label mb-20 mt-5 flex-shrink-0">可视化显示</div>
        <div v-else class="mb-20 mt-5 flex-shrink-0 text-16 color-#140D35 font-bold">
          可视化显示
        </div>
        <div ref="$visualizeContainer" class="relative flex-1">
          <template v-if="special">
            <div
              class="absolute bottom-0 left-0 right-0 top-0 z-100 m-auto flex items-center justify-center text-24"
            >
              暂不支持
            </div>
          </template>
          <template v-else>
            <div :class="['toggle', appStore.isDeep ? 'deep' : 'light']" @click="toggle">
              <img
                :src="
                  isFullscreen
                    ? appStore.isDeep
                      ? deepResetImg
                      : lightResetImg
                    : appStore.isDeep
                    ? deepFullImg
                    : lightFullImg
                "
              />
              {{ isFullscreen ? '还原' : '全屏' }}
            </div>
            <iframe
              ref="iframe"
              class="wh-full"
              :src="visualizeSrc"
              frameborder="0"
              scolling="no"
            ></iframe>
          </template>
        </div>
      </div>
    </div>
    <Teleport v-if="isMounted" to="#step-control">
      <div class="my-btn-group mt-32">
        <n-button
          v-if="testStatus == 1 && !special"
          :color="appStore.buttonColor"
          @click="stopTest"
        >
          终止测试
        </n-button>
        <n-button v-else :color="appStore.buttonColor" @click="backHome">返回首页</n-button>
      </div>
    </Teleport>
  </div>
</template>
<script setup lang="jsx">
import { useAppStore } from '@/store'
import lightFullImg from '@/assets/images/light-full.png'
import lightResetImg from '@/assets/images/light-reset.png'
import deepFullImg from '@/assets/images/deep-full.png'
import deepResetImg from '@/assets/images/deep-reset.png'
import { useFullscreen } from '@vueuse/core'
import { uniqBy } from 'lodash-es'
import * as testObjectApi from '@/api/testObject'
import * as testRecordApi from '@/api/testRecord'
import { useMqttStore } from '@/store'
import { useMounted } from '@/hooks/useMounted'
import { lightColorMap, deepColorMap } from '@/enum/process'
import { specialSimulatorValues, notEvaluateSimulatorValues } from '@/enum/simulator'
defineOptions({
  name: 'ExecuteTest',
})
const appStore = useAppStore()
const emits = defineEmits(['next', 'prev'])
const props = defineProps({
  id: {
    type: String,
    default: null,
  },
})

const { isMounted } = useMounted()

const type = ref('static')
const height = computed(() => (type.value === 'static' ? 450 : 400))
const simulator = ref(null)
const special = computed(() => specialSimulatorValues.includes(simulator.value))
async function getInfo() {
  const { data } = await testRecordApi.info(props.id)
  type.value = data.testModeId === '2' ? 'static' : 'dynamic'
  simulator.value = data.simulator
  if (specialSimulatorValues.includes(data.simulator)) {
    // 开启定时器
    timer = setInterval(() => {
      getProgressInfoSpecial(data.specialId)
    }, 1000)
  } else {
    // 开启定时器
    timer = setInterval(() => {
      getProgressInfo()
    }, 1000)
  }
  // 开启订阅
  getOutputList().then(() => {
    mqttStore.subscribe({
      topic: currentTopic.value,
      callback(_, msg) {
        // console.log(outputState, msg)
        if (outputState.current === outputState.pages || outputState.pages === 0) {
          try {
            outputState.list.push(JSON.parse(msg))
            nextTick(() => {
              $output.value.scrollTo({ top: height.value })
            })
          } catch (error) {
            console.log('error', error)
          }
        }
      },
    })
  })
}

// 轮询查取进度
let timer = null
const progress = ref(0)
/**
 *  0：完成
 *  1：处理中
 *  2：异常
 *  3：终止
 *  4：暂停
 */
const testStatus = ref(1)
const lightStatusMap = {
  0: {
    text: '测试完成',
    ...lightColorMap.complete,
  },
  1: {
    text: '测试中',
    ...lightColorMap.processing,
  },
  2: {
    text: '测试失败',
    ...lightColorMap.error,
  },
  3: {
    text: '测试终止',
    ...lightColorMap.error,
  },
  4: {
    color: '#ffce45',
    text: '测试暂停',
    processing: false,
  },
}
const deepStatusMap = {
  0: {
    text: '测试完成',
    ...deepColorMap.complete,
  },
  1: {
    text: '测试中',
    ...deepColorMap.processing,
  },
  2: {
    text: '测试失败',
    ...deepColorMap.error,
  },
  3: {
    text: '测试终止',
    ...deepColorMap.error,
  },
  4: {
    color: '#ffce45',
    text: '测试暂停',
    processing: false,
  },
}
const statusResult = computed(() => {
  return (appStore.isDeep ? deepStatusMap : lightStatusMap)[testStatus.value]
})
function getProgressInfo() {
  testRecordApi
    .progressInfo(props.id)
    .then((res) => {
      const last = res.data.testProgress.at(-1)
      progress.value = last['progress']
      testStatus.value = last['testStatus']
      if (last.testStatus != 1) {
        clearInterval(timer)
        timer = null
      }
      if (last.testStatus == 0) {
        emits('next')
      }
    })
    .catch(() => {
      clearInterval(timer)
      timer = null
    })
}

function getProgressInfoSpecial(executeId) {
  testRecordApi
    .progressInfoSpecial({ id: props.id, executeId })
    .then((res) => {
      const last = res.data
      progress.value = last['progress']
      testStatus.value = last['testStatus']
      if (last.testStatus != 1) {
        clearInterval(timer)
        timer = null
      }
      if (last.testStatus == 0) {
        //测试完成自动跳转，启明星不用跳转
        if (!notEvaluateSimulatorValues.includes(simulator.value)) {
          emits('next')
        }
      }
    })
    .catch(() => {
      clearInterval(timer)
      timer = null
    })
}

//获取执行输出,订阅
const $output = ref(null)
const mqttStore = useMqttStore()
const currentTopic = computed(() => `test-${props.id}`)
const outputState = reactive({
  current: 1,
  pages: 1,
  size: 30,
  tabs: [],
  list: [],
  loading: false,
  currentTab: null,
})
const currentTabList = computed(() =>
  outputState.list.filter((item) => {
    if (outputState.currentTab) {
      return item['executeNum'] === outputState.currentTab
    } else {
      return true
    }
  })
)
async function getOutputList() {
  outputState.loading = true
  const { data } = await testObjectApi.executeOutputList({
    testId: props.id,
    current: outputState.current,
    size: outputState.size,
  })
  outputState.pages = data.pages
  outputState.list = data.current === 1 ? data.records : outputState.list.concat(data.records)
  outputState.tabs = uniqBy(outputState.list, 'executeNum').map((item) => ({
    label: `#${item.executeNum}`,
    value: item.executeNum,
  }))
  outputState.currentTab = outputState.tabs.length ? outputState.tabs[0]['value'] : null
  outputState.loading = false
}

function onScroll(e) {
  const dom = e.target
  const scrollDistance = dom.scrollHeight - dom.scrollTop - dom.clientHeight
  if (scrollDistance <= 1) {
    handleScroll()
  }
}
function handleScroll() {
  if (outputState.current <= outputState.pages - 1 && !outputState.loading) {
    outputState.current++
    getOutputList()
  }
}

function stopTest() {
  testRecordApi
    .stopTest(props.id)
    .then(() => {
      $message.success('终止测试成功!')
      getProgressInfo()
    })
    .catch((err) => {
      console.log(err)
      $message.error('终止测试失败!')
    })
}

const router = useRouter()
function backHome() {
  router.replace('/test')
}

onBeforeMount(() => {
  getInfo()
})
onBeforeUnmount(() => {
  // 取消定时器
  if (timer) {
    clearInterval(timer)
    timer = null
  }
  // 取消订阅
  mqttStore.unsubscribe(currentTopic.value)
})

//可视化显示
const visualizeSrc = ref('http://172.22.63.211:80')
const $visualizeContainer = ref(null)
const { isFullscreen, toggle } = useFullscreen($visualizeContainer)
</script>
<style lang="scss" scoped>
.output :deep(.n-form-item-blank) {
  flex-direction: column;
  align-items: flex-start;
}

.output-text {
  width: 100%;
  white-space: normal;
  word-break: break-all;
  word-wrap: break-word;
}
.deep-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 16px;
  color: #4ddef4;
  &::before {
    content: '';
    display: block;
    width: 25px;
    height: 18px;
    background: url(@/assets/images/deep-title-icon.png);
  }
}
.toggle {
  height: 32px;
  width: 80px;
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  &.light {
    border-radius: 6px;
    background: #fff;
    border: 1px solid #e7eaf0;
  }
  &.deep {
    color: #2ba1ff;
    border: 1px solid #2ba1ff;
  }
}
</style>
